/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi_flash.c
  * @brief   SPI Flash读写模块实现
  *          支持W25Q系列、AT25系列等SPI Flash芯片
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "spi_flash.h"

/* Private variables ---------------------------------------------------------*/
static uint8_t flash_initialized = 0;

/* Private function prototypes -----------------------------------------------*/
static HAL_StatusTypeDef SPI_Flash_SendCommand(uint8_t cmd);
static HAL_StatusTypeDef SPI_Flash_SendAddress(uint32_t addr);

/**
 * @brief  SPI Flash初始化
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 修正：配置CS引脚 - 使用GPIOB时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();  // 改为GPIOB
    GPIO_InitStruct.Pin = FLASH_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(FLASH_CS_PORT, &GPIO_InitStruct);
    
    // CS引脚初始化为高电平
    SPI_Flash_CS_High();
    
    // 退出掉电模式
    SPI_Flash_ReleasePowerDown();
    HAL_Delay(1);
    
    // 检查Flash是否响应
    uint8_t jedec_id[3];
    if (SPI_Flash_ReadID(jedec_id) == HAL_OK)
    {
        flash_initialized = 1;
        return HAL_OK;
    }
    
    return HAL_ERROR;
}

/**
 * @brief  发送命令
 * @param  cmd: 命令字节
 * @retval HAL_StatusTypeDef 状态
 */
static HAL_StatusTypeDef SPI_Flash_SendCommand(uint8_t cmd)
{
    return HAL_SPI_Transmit(FLASH_SPI_HANDLE, &cmd, 1, FLASH_TIMEOUT);
}

/**
 * @brief  发送地址
 * @param  addr: 24位地址
 * @retval HAL_StatusTypeDef 状态
 */
static HAL_StatusTypeDef SPI_Flash_SendAddress(uint32_t addr)
{
    uint8_t addr_bytes[3];
    addr_bytes[0] = (addr >> 16) & 0xFF;
    addr_bytes[1] = (addr >> 8) & 0xFF;
    addr_bytes[2] = addr & 0xFF;
    
    return HAL_SPI_Transmit(FLASH_SPI_HANDLE, addr_bytes, 3, FLASH_TIMEOUT);
}

/**
 * @brief  读取JEDEC ID
 * @param  jedec_id: JEDEC ID缓冲区(3字节)
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReadID(uint8_t *jedec_id)
{
    HAL_StatusTypeDef status;
    
    if (jedec_id == NULL)
    {
        return HAL_ERROR;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_JEDEC_ID);
    if (status == HAL_OK)
    {
        status = HAL_SPI_Receive(FLASH_SPI_HANDLE, jedec_id, 3, FLASH_TIMEOUT);
    }
    
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  读取设备ID
 * @param  device_id: 设备ID缓冲区(2字节)
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReadDeviceID(uint8_t *device_id)
{
    HAL_StatusTypeDef status;
    uint8_t dummy_addr[3] = {0x00, 0x00, 0x00};
    
    if (device_id == NULL)
    {
        return HAL_ERROR;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_DEVICE_ID);
    if (status == HAL_OK)
    {
        status = HAL_SPI_Transmit(FLASH_SPI_HANDLE, dummy_addr, 3, FLASH_TIMEOUT);
        if (status == HAL_OK)
        {
            status = HAL_SPI_Receive(FLASH_SPI_HANDLE, device_id, 2, FLASH_TIMEOUT);
        }
    }
    
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  读取状态寄存器
 * @retval uint8_t 状态寄存器值
 */
uint8_t SPI_Flash_ReadStatus(void)
{
    uint8_t status = 0;
    
    SPI_Flash_CS_Low();
    
    SPI_Flash_SendCommand(FLASH_CMD_READ_STATUS);
    HAL_SPI_Receive(FLASH_SPI_HANDLE, &status, 1, FLASH_TIMEOUT);
    
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  等待Flash操作完成
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WaitForReady(void)
{
    uint32_t timeout = HAL_GetTick() + FLASH_TIMEOUT;
    
    while (HAL_GetTick() < timeout)
    {
        if ((SPI_Flash_ReadStatus() & FLASH_STATUS_BUSY) == 0)
        {
            return HAL_OK;
        }
        HAL_Delay(1);
    }
    
    return HAL_TIMEOUT;
}

/**
 * @brief  写使能
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WriteEnable(void)
{
    HAL_StatusTypeDef status;
    
    SPI_Flash_CS_Low();
    status = SPI_Flash_SendCommand(FLASH_CMD_WRITE_ENABLE);
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  写禁止
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WriteDisable(void)
{
    HAL_StatusTypeDef status;
    
    SPI_Flash_CS_Low();
    status = SPI_Flash_SendCommand(FLASH_CMD_WRITE_DISABLE);
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  读取数据
 * @param  addr: 读取地址
 * @param  data: 数据缓冲区
 * @param  size: 读取字节数
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReadData(uint32_t addr, uint8_t *data, uint32_t size)
{
    HAL_StatusTypeDef status;
    
    if (!flash_initialized || data == NULL || size == 0)
    {
        return HAL_ERROR;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_READ_DATA);
    if (status == HAL_OK)
    {
        status = SPI_Flash_SendAddress(addr);
        if (status == HAL_OK)
        {
            status = HAL_SPI_Receive(FLASH_SPI_HANDLE, data, size, FLASH_TIMEOUT);
        }
    }
    
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  快速读取数据
 * @param  addr: 读取地址
 * @param  data: 数据缓冲区
 * @param  size: 读取字节数
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_FastRead(uint32_t addr, uint8_t *data, uint32_t size)
{
    HAL_StatusTypeDef status;
    uint8_t dummy = 0xFF;
    
    if (!flash_initialized || data == NULL || size == 0)
    {
        return HAL_ERROR;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_FAST_READ);
    if (status == HAL_OK)
    {
        status = SPI_Flash_SendAddress(addr);
        if (status == HAL_OK)
        {
            // 发送dummy字节
            status = HAL_SPI_Transmit(FLASH_SPI_HANDLE, &dummy, 1, FLASH_TIMEOUT);
            if (status == HAL_OK)
            {
                status = HAL_SPI_Receive(FLASH_SPI_HANDLE, data, size, FLASH_TIMEOUT);
            }
        }
    }
    
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  页编程
 * @param  addr: 写入地址
 * @param  data: 数据缓冲区
 * @param  size: 写入字节数(不超过页大小)
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_PageProgram(uint32_t addr, uint8_t *data, uint32_t size)
{
    HAL_StatusTypeDef status;
    
    if (!flash_initialized || data == NULL || size == 0 || size > FLASH_PAGE_SIZE)
    {
        return HAL_ERROR;
    }
    
    // 写使能
    status = SPI_Flash_WriteEnable();
    if (status != HAL_OK)
    {
        return status;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_PAGE_PROGRAM);
    if (status == HAL_OK)
    {
        status = SPI_Flash_SendAddress(addr);
        if (status == HAL_OK)
        {
            status = HAL_SPI_Transmit(FLASH_SPI_HANDLE, data, size, FLASH_TIMEOUT);
        }
    }
    
    SPI_Flash_CS_High();
    
    if (status == HAL_OK)
    {
        status = SPI_Flash_WaitForReady();
    }
    
    return status;
}

/**
 * @brief  写入数据(自动处理跨页)
 * @param  addr: 写入地址
 * @param  data: 数据缓冲区
 * @param  size: 写入字节数
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_WriteData(uint32_t addr, uint8_t *data, uint32_t size)
{
    HAL_StatusTypeDef status = HAL_OK;
    uint32_t bytes_written = 0;
    uint32_t current_addr = addr;
    uint32_t page_remaining;
    uint32_t write_size;
    
    if (!flash_initialized || data == NULL || size == 0)
    {
        return HAL_ERROR;
    }
    
    while (bytes_written < size && status == HAL_OK)
    {
        // 计算当前页剩余空间
        page_remaining = FLASH_PAGE_SIZE - (current_addr % FLASH_PAGE_SIZE);
        
        // 确定本次写入大小
        write_size = (size - bytes_written) > page_remaining ? page_remaining : (size - bytes_written);
        
        // 页编程
        status = SPI_Flash_PageProgram(current_addr, &data[bytes_written], write_size);
        
        if (status == HAL_OK)
        {
            bytes_written += write_size;
            current_addr += write_size;
        }
    }
    
    return status;
}

/**
 * @brief  扇区擦除(4KB)
 * @param  addr: 扇区地址
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_SectorErase(uint32_t addr)
{
    HAL_StatusTypeDef status;
    
    if (!flash_initialized)
    {
        return HAL_ERROR;
    }
    
    // 写使能
    status = SPI_Flash_WriteEnable();
    if (status != HAL_OK)
    {
        return status;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_SECTOR_ERASE);
    if (status == HAL_OK)
    {
        status = SPI_Flash_SendAddress(addr);
    }
    
    SPI_Flash_CS_High();
    
    if (status == HAL_OK)
    {
        status = SPI_Flash_WaitForReady();
    }
    
    return status;
}

/**
 * @brief  块擦除(32KB)
 * @param  addr: 块地址
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_BlockErase32K(uint32_t addr)
{
    HAL_StatusTypeDef status;
    
    if (!flash_initialized)
    {
        return HAL_ERROR;
    }
    
    // 写使能
    status = SPI_Flash_WriteEnable();
    if (status != HAL_OK)
    {
        return status;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_BLOCK_ERASE_32K);
    if (status == HAL_OK)
    {
        status = SPI_Flash_SendAddress(addr);
    }
    
    SPI_Flash_CS_High();
    
    if (status == HAL_OK)
    {
        status = SPI_Flash_WaitForReady();
    }
    
    return status;
}

/**
 * @brief  块擦除(64KB)
 * @param  addr: 块地址
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_BlockErase64K(uint32_t addr)
{
    HAL_StatusTypeDef status;
    
    if (!flash_initialized)
    {
        return HAL_ERROR;
    }
    
    // 写使能
    status = SPI_Flash_WriteEnable();
    if (status != HAL_OK)
    {
        return status;
    }
    
    SPI_Flash_CS_Low();
    
    status = SPI_Flash_SendCommand(FLASH_CMD_BLOCK_ERASE_64K);
    if (status == HAL_OK)
    {
        status = SPI_Flash_SendAddress(addr);
    }
    
    SPI_Flash_CS_High();
    
    if (status == HAL_OK)
    {
        status = SPI_Flash_WaitForReady();
    }
    
    return status;
}

/**
 * @brief  芯片擦除
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ChipErase(void)
{
    HAL_StatusTypeDef status;
    
    if (!flash_initialized)
    {
        return HAL_ERROR;
    }
    
    // 写使能
    status = SPI_Flash_WriteEnable();
    if (status != HAL_OK)
    {
        return status;
    }
    
    SPI_Flash_CS_Low();
    status = SPI_Flash_SendCommand(FLASH_CMD_CHIP_ERASE);
    SPI_Flash_CS_High();
    
    if (status == HAL_OK)
    {
        status = SPI_Flash_WaitForReady();
    }
    
    return status;
}

/**
 * @brief  进入掉电模式
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_PowerDown(void)
{
    HAL_StatusTypeDef status;
    
    SPI_Flash_CS_Low();
    status = SPI_Flash_SendCommand(FLASH_CMD_POWER_DOWN);
    SPI_Flash_CS_High();
    
    return status;
}

/**
 * @brief  退出掉电模式
 * @retval HAL_StatusTypeDef 状态
 */
HAL_StatusTypeDef SPI_Flash_ReleasePowerDown(void)
{
    HAL_StatusTypeDef status;
    
    SPI_Flash_CS_Low();
    status = SPI_Flash_SendCommand(FLASH_CMD_RELEASE_POWER_DOWN);
    SPI_Flash_CS_High();
    
    return status;
}